package cn.rongcloud.im.utils.qrcode.barcodescanner;

import android.content.Context;
import android.content.Intent;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.widget.FrameLayout;
import android.widget.TextView;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ResultPoint;

import java.util.List;
import java.util.Map;
import java.util.Set;

import cn.rongcloud.im.R;
import cn.rongcloud.im.utils.qrcode.barcodescanner.camera.CameraSettings;
import cn.rongcloud.im.utils.qrcode.client.DecodeFormatManager;
import cn.rongcloud.im.utils.qrcode.client.DecodeHintManager;
import cn.rongcloud.im.utils.qrcode.client.Intents;

/**
 * Encapsulates BarcodeView, ViewfinderView and status text.
 * <p>
 * To customize the UI, use BarcodeView and ViewfinderView directly.
 */
public class DecoratedBarcodeView extends FrameLayout {
    private BarcodeView barcodeView;
    private NewViewfinderView viewFinder;

    /**
     * The instance of @link TorchListener to send events callback.
     */
    private TorchListener torchListener;

    private class WrappedCallback implements BarcodeCallback {
        private BarcodeCallback delegate;

        public WrappedCallback(BarcodeCallback delegate) {
            this.delegate = delegate;
        }

        @Override
        public void barcodeResult(BarcodeResult result) {
            delegate.barcodeResult(result);
        }

        @Override
        public void possibleResultPoints(List<ResultPoint> resultPoints) {
            for (ResultPoint point : resultPoints) {
                viewFinder.addPossibleResultPoint(point);
            }
            delegate.possibleResultPoints(resultPoints);
        }
    }

    public DecoratedBarcodeView(Context context) {
        super(context);
        initialize();
    }

    public DecoratedBarcodeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize(attrs);
    }

    public DecoratedBarcodeView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize(attrs);
    }

    /**
     * Initialize the view with the xml configuration based on styleable attributes.
     *
     * @param attrs The attributes to use on view.
     */
    private void initialize(AttributeSet attrs) {
        // Get attributes set on view
        TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.zxing_view);

        int scannerLayout = attributes.getResourceId(
                R.styleable.zxing_view_zxing_scanner_layout, R.layout.zxing_barcode_scanner);

        attributes.recycle();

        inflate(getContext(), scannerLayout, this);

        barcodeView = (BarcodeView) findViewById(R.id.zxing_barcode_surface);

        if (barcodeView == null) {
            throw new IllegalArgumentException(
                    "There is no a BarcodeView on provided layout " +
                            "with the id \"zxing_barcode_surface\".");
        }

        // Pass on any preview-related attributes
        barcodeView.initializeAttributes(attrs);


        viewFinder = (NewViewfinderView) findViewById(R.id.zxing_viewfinder_view);

        if (viewFinder == null) {
            throw new IllegalArgumentException(
                    "There is no a ViewfinderView on provided layout " +
                            "with the id \"zxing_viewfinder_view\".");
        }

        viewFinder.setCameraPreview(barcodeView);

    }

    /**
     * Initialize with no custom attributes setted.
     */
    private void initialize() {
        initialize(null);
    }

    /**
     * Convenience method to initialize camera id, decode formats and prompt message from an intent.
     *
     * @param intent the intent, as generated by IntentIntegrator
     */
    public void initializeFromIntent(Intent intent) {
        // Scan the formats the intent requested, and return the result to the calling activity.
        Set<BarcodeFormat> decodeFormats = DecodeFormatManager.parseDecodeFormats(intent);
        Map<DecodeHintType, Object> decodeHints = DecodeHintManager.parseDecodeHints(intent);

        CameraSettings settings = new CameraSettings();

        if (intent.hasExtra(Intents.Scan.CAMERA_ID)) {
            int cameraId = intent.getIntExtra(Intents.Scan.CAMERA_ID, -1);
            if (cameraId >= 0) {
                settings.setRequestedCameraId(cameraId);
            }
        }

        // Check to see if the scan should be inverted.
        boolean inverted = intent.getBooleanExtra(Intents.Scan.INVERTED_SCAN, false);

        String characterSet = intent.getStringExtra(Intents.Scan.CHARACTER_SET);

        MultiFormatReader reader = new MultiFormatReader();
        reader.setHints(decodeHints);

        barcodeView.setCameraSettings(settings);
        barcodeView.setDecoderFactory(new DefaultDecoderFactory(decodeFormats, decodeHints, characterSet, inverted));
    }

    /**
     * @see BarcodeView#pause()
     */
    public void pause() {
        barcodeView.pause();
    }

    /**
     * @see BarcodeView#resume()
     */
    public void resume() {
        barcodeView.resume();
    }

    public BarcodeView getBarcodeView() {
        return (BarcodeView) findViewById(R.id.zxing_barcode_surface);
    }

    public NewViewfinderView getViewFinder() {
        return viewFinder;
    }

    /**
     * @see BarcodeView#decodeSingle(BarcodeCallback)
     */
    public void decodeSingle(BarcodeCallback callback) {
        barcodeView.decodeSingle(new WrappedCallback(callback));
    }

    /**
     * @see BarcodeView#decodeContinuous(BarcodeCallback)
     */
    public void decodeContinuous(BarcodeCallback callback) {
        barcodeView.decodeContinuous(new WrappedCallback(callback));
    }

    /**
     * 是否停止解码，但不停止预览。
     */
    public void stopDecoding(){
        barcodeView.stopDecoding();
    }

    /**
     * Turn on the device's flashlight. 开灯
     */
    public void setTorchOn() {
        barcodeView.setTorch(true);

        if (torchListener != null) {
            torchListener.onTorchOn();
        }
    }

    /**
     * Turn off the device's flashlight. 关灯
     */
    public void setTorchOff() {
        barcodeView.setTorch(false);

        if (torchListener != null) {
            torchListener.onTorchOff();
        }
    }

    public void setTorchListener(TorchListener listener) {
        this.torchListener = listener;
    }

    /**
     * The Listener to torch/fflashlight events (turn on, turn off).
     */
    public interface TorchListener {

        void onTorchOn();

        void onTorchOff();
    }
}
